﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Common.Logging;

namespace Wicresoft.Task.EmployeeSync
{


    //对有序的数据进行处理
    public static class ArithmeticHelper<T>
    {

        public delegate void HandlerCreateEntry(T sourceEntity);
        public delegate void HandlerModifyEntry(T sourceEntity, T destinationEntity);   //注意除去没有变化的部分
        public delegate void HandlerDeleteEntry(T destinationEntity);

        public static void Traverse(IList<T> source, IList<T> destination, HandlerCreateEntry create, HandlerModifyEntry modify, HandlerDeleteEntry delete, PropertyInfo key = null)
        {
            if (key == null) key = typeof(T).GetProperties().FirstOrDefault(p => p.GetCustomAttributes(false).Any(a => a is ArithmeticKeyAttribute));

            if (key == null)
                throw new ArgumentException("source or destination's generic type must contains at least one property that is decorated with ArithmeticKeyAttribute.");

            var fastInvoker = new DynamicMethodExecutor(key.GetGetMethod());

            if (key.PropertyType.ToString() == typeof(int).ToString())
            {
                TraverseInt(source, destination, create, modify, delete, fastInvoker);
            }
            else if (key.PropertyType.ToString() == typeof(string).ToString())
            {
                TraverseString(source, destination, create, modify, delete, fastInvoker);
            }
            else
            {
                throw new NotImplementedException();
            }

            //根据key 判定调用哪个方法
        }

        private static void TraverseString(IList<T> source, IList<T> destination, HandlerCreateEntry create, HandlerModifyEntry modify, HandlerDeleteEntry delete, DynamicMethodExecutor fastInvoker)
        {
            if (source == null || destination == null || create == null || modify == null || delete == null || fastInvoker == null)
                throw new ArgumentNullException("source, destination, create, modify, delete,fastInvoker");

            var sourceOrderBy = source.OrderBy(o => (string)fastInvoker.Execute(o, null));
            var destinationOrderBy = destination.OrderBy(o => (string)fastInvoker.Execute(o, null));

            // begin of algorithm
            string sourceKey = string.Empty;
            string destinationKey = string.Empty;

            IEnumerator<T> sourceEnumerator = sourceOrderBy.GetEnumerator();
            IEnumerator<T> destinationEnumerator = destinationOrderBy.GetEnumerator();

            T sourceEntry = default(T);
            T destinationEntry = default(T);


            bool isNotDestinationFinal = destinationEnumerator.MoveNext();
            bool isNotSourceFinal = sourceEnumerator.MoveNext();
            if (isNotSourceFinal)
            {
                sourceEntry = sourceEnumerator.Current;
                sourceKey = fastInvoker.Execute(sourceEntry, null) as string;
            }
            if (isNotDestinationFinal)
            {
                destinationEntry = destinationEnumerator.Current;
                destinationKey = fastInvoker.Execute(destinationEntry, null) as string;
            }

            while (isNotSourceFinal)
            {

                if (destinationKey.Equals(sourceKey, StringComparison.InvariantCultureIgnoreCase) && isNotDestinationFinal)
                {
                    modify(sourceEntry, destinationEntry);
                    isNotDestinationFinal = destinationEnumerator.MoveNext();
                    if (isNotDestinationFinal)
                    {
                        destinationEntry = destinationEnumerator.Current;
                        destinationKey = fastInvoker.Execute(destinationEntry, null) as string;
                    }

                    isNotSourceFinal = sourceEnumerator.MoveNext();
                    if (isNotSourceFinal)
                    {
                        sourceEntry = sourceEnumerator.Current;
                        sourceKey = fastInvoker.Execute(sourceEntry, null) as string;
                    }
                }
                else if (sourceKey.CompareTo(destinationKey) > 0 && isNotDestinationFinal)
                {
                    delete(destinationEntry);
                    isNotDestinationFinal = destinationEnumerator.MoveNext();
                    if (isNotDestinationFinal)
                    {
                        destinationEntry = destinationEnumerator.Current;
                        destinationKey = fastInvoker.Execute(destinationEntry, null) as string;
                    }
                }
                else
                {
                    create(sourceEntry);

                    isNotSourceFinal = sourceEnumerator.MoveNext();
                    if (isNotSourceFinal)
                    {
                        sourceEntry = sourceEnumerator.Current;
                        sourceKey = fastInvoker.Execute(sourceEntry, null) as string;
                    }
                }
            }

            while (isNotDestinationFinal)
            {
                T toBeDelete = destinationEnumerator.Current;
                delete(toBeDelete);
                isNotDestinationFinal = destinationEnumerator.MoveNext();
            }
            // end of algorithm
        }

        private static void TraverseInt(IList<T> source, IList<T> destination, HandlerCreateEntry create, HandlerModifyEntry modify, HandlerDeleteEntry delete, DynamicMethodExecutor fastInvoker)
        {
            if (source == null || destination == null || create == null || modify == null || delete == null || fastInvoker == null)
                throw new ArgumentNullException("source, destination, create, modify, delete,fastInvoker");

            var sourceOrderBy = source.OrderBy(o => (int)fastInvoker.Execute(o, null));
            var destinationOrderBy = destination.OrderBy(o => (int)fastInvoker.Execute(o, null));

            // begin of algorithm
            int sourceKey = default(int);
            int destinationKey = default(int);

            IEnumerator<T> sourceEnumerator = sourceOrderBy.GetEnumerator();
            IEnumerator<T> destinationEnumerator = destinationOrderBy.GetEnumerator();

            T sourceEntry = default(T);
            T destinationEntry = default(T);


            bool isNotDestinationFinal = destinationEnumerator.MoveNext();
            bool isNotSourceFinal = sourceEnumerator.MoveNext();
            if (isNotSourceFinal)
            {
                sourceEntry = sourceEnumerator.Current;
                sourceKey = (int)fastInvoker.Execute(sourceEntry, null);
            }
            if (isNotDestinationFinal)
            {
                destinationEntry = destinationEnumerator.Current;
                destinationKey = (int)fastInvoker.Execute(destinationEntry, null);
            }

            while (isNotSourceFinal)
            {

                if (destinationKey == sourceKey && isNotDestinationFinal)
                {
                    modify(sourceEntry, destinationEntry);
                    isNotDestinationFinal = destinationEnumerator.MoveNext();
                    if (isNotDestinationFinal)
                    {
                        destinationEntry = destinationEnumerator.Current;
                        destinationKey = (int)fastInvoker.Execute(destinationEntry, null);
                    }

                    isNotSourceFinal = sourceEnumerator.MoveNext();
                    if (isNotSourceFinal)
                    {
                        sourceEntry = sourceEnumerator.Current;
                        sourceKey = (int)fastInvoker.Execute(sourceEntry, null);
                    }
                }
                else if (sourceKey > destinationKey && isNotDestinationFinal)
                {
                    delete(destinationEntry);
                    isNotDestinationFinal = destinationEnumerator.MoveNext();
                    if (isNotDestinationFinal)
                    {
                        destinationEntry = destinationEnumerator.Current;
                        destinationKey = (int)fastInvoker.Execute(destinationEntry, null);
                    }
                }
                else
                {
                    create(sourceEntry);

                    isNotSourceFinal = sourceEnumerator.MoveNext();
                    if (isNotSourceFinal)
                    {
                        sourceEntry = sourceEnumerator.Current;
                        sourceKey = (int)fastInvoker.Execute(sourceEntry, null);
                    }
                }
            }

            while (isNotDestinationFinal)
            {
                T toBeDelete = destinationEnumerator.Current;
                delete(toBeDelete);
                isNotDestinationFinal = destinationEnumerator.MoveNext();
            }
            // end of algorithm
        }
    }
}
